package utils

import (
	errors2 "github.com/pkg/errors"
	"io"
	"io/fs"
	"os"
	"path/filepath"
	"strings"
)

type FileInfo struct {
	RealPath string
	IsDir    bool
	Handle   *os.File
}

func (fileInfo FileInfo) Create() error {
	if ok := Exists(fileInfo.RealPath); ok {
		return nil
	}
	if fileInfo.IsDir {
		err := CreateDir(fileInfo.RealPath)
		return err
	} else {
		file, err := os.Create(fileInfo.RealPath)
		if err != nil {
			return errors2.WithMessage(err, "Create: create file failed!")
		}
		_, err = io.Copy(file, fileInfo.Handle)
		if err != nil {
			return errors2.WithMessage(err, "Create: copy file failed!")
		}
	}
	return nil
}

func CopyFileInfoToChan(sourcePath, destPath string, ch chan *FileInfo) error {
	defer close(ch)
	filepath.Walk(sourcePath, func(path string, info fs.FileInfo, err error) error {
		var fileInfo FileInfo
		realPath := strings.ReplaceAll(path, sourcePath, destPath)
		fileInfo.RealPath = realPath
		if info.IsDir() {
			fileInfo.IsDir = true
		} else {
			fileInfo.IsDir = false
			file, err := os.Open(path)
			if err != nil {
				panic(err)
			}
			fileInfo.Handle = file
		}
		ch <- &fileInfo
		return nil
	})
	return nil
}

func CopyDir(sourcePath, destPath string) error {
	ch := make(chan *FileInfo)
	go CopyFileInfoToChan(sourcePath, destPath, ch)
	for info := range ch {
		err := info.Create()
		if err != nil {
			return err
		}
	}
	return nil
}
